{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Figure 1 - Simple Inconsistency Example\n",
    "\n",
    "Here we create synthetic data to make XGBoost build the Model A and Model B from Figure 1 of the Tree SHAP paper. We then compute both individualized feature importances using Tree SHAP and Saabas, and global feature importances using Tree SHAP, gain, split count, and permutation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as pl\n",
    "import numpy as np\n",
    "import shap\n",
    "import xgboost as xgb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Model A\n",
    "\n",
    "This is just a simple AND function with a small amount of noise to force the creation of the left child split. Feature 0 is Fever and feature 1 is Cough."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "N = 2000\n",
    "X = np.zeros((N,2))\n",
    "X[:1000,0] = 1\n",
    "X[:500,1] = 1\n",
    "X[1000:1500,1] = 1\n",
    "yA = 80 * (X[:,0] * X[:,1]) + 1e-4 * ((X[:,0] == 0) * (X[:,1] == 0)) # last term forces the creation of left split\n",
    "Xd = xgb.DMatrix(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0:[f0<0.5] yes=1,no=2,missing=1,gain=799998,cover=2000\n",
      "\t1:[f1<0.5] yes=3,no=4,missing=3,gain=2.5e-06,cover=1000\n",
      "\t\t3:leaf=0.0001,cover=500\n",
      "\t\t4:leaf=-0,cover=500\n",
      "\t2:[f1<0.5] yes=5,no=6,missing=5,gain=1.6e+06,cover=1000\n",
      "\t\t5:leaf=-0,cover=500\n",
      "\t\t6:leaf=80,cover=500\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# train a model with single tree\n",
    "XdA = xgb.DMatrix(X, label=yA)\n",
    "modelA = xgb.train({\n",
    "    'eta': 1, 'max_depth': 3, 'base_score': 0, \"lambda\": 0\n",
    "}, XdA, 1)\n",
    "print(modelA.get_dump(with_stats=True)[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Model B\n",
    "\n",
    "This is identical to Model A, except Cough is more important because it has its own marginal effect in addition to the original AND function in Model A."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "yB = yA + X[:,1] * 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0:[f1<0.5] yes=1,no=2,missing=1,gain=1.25e+06,cover=2000\n",
      "\t1:[f0<0.5] yes=3,no=4,missing=3,gain=2.5e-06,cover=1000\n",
      "\t\t3:leaf=0.0001,cover=500\n",
      "\t\t4:leaf=-0,cover=500\n",
      "\t2:[f0<0.5] yes=5,no=6,missing=5,gain=1.6e+06,cover=1000\n",
      "\t\t5:leaf=10,cover=500\n",
      "\t\t6:leaf=90,cover=500\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# train a model with single tree\n",
    "XdB = xgb.DMatrix(X, label=yB)\n",
    "modelB = xgb.train({\n",
    "    'eta': 1, 'max_depth': 3, 'base_score': 0, \"lambda\": 0\n",
    "}, XdB, 1)\n",
    "print(modelB.get_dump(with_stats=True)[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SHAP Values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 29.99998665,  29.99998665,  20.0000248 ], dtype=float32)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "shap_valuesA = modelA.predict(Xd, pred_contribs=True)\n",
    "shap_valuesA[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 29.99998665,  34.99998856,  25.0000248 ], dtype=float32)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "shap_valuesB = modelB.predict(Xd, pred_contribs=True)\n",
    "shap_valuesB[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Saabas Values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 19.9999752,  40.       ,  20.0000248], dtype=float32)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "saabas_valuesA = modelA.predict(Xd, pred_contribs=True, approx_contribs=True)\n",
    "saabas_valuesA[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 40.       ,  24.9999752,  25.0000248], dtype=float32)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "saabas_valuesB = modelB.predict(Xd, pred_contribs=True, approx_contribs=True)\n",
    "saabas_valuesB[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## mean(abs(SHAP Values))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 19.99999809,  19.99999809,  20.00000191], dtype=float32)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.abs(shap_valuesA).mean(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 19.99999809,  24.99999809,  25.00000191], dtype=float32)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.abs(shap_valuesB).mean(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## mean(abs(Saabas Values))\n",
    "\n",
    "Note that the mean absolute Saabas values happen to be identical to the mean absolute SHAP values in this simple example, but in general this is not true."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 19.99999809,  20.        ,  20.00000191], dtype=float32)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.abs(saabas_valuesA).mean(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 20.        ,  24.99999809,  25.00000191], dtype=float32)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.abs(saabas_valuesB).mean(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Split count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 2)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp = modelA.get_score(importance_type=\"weight\")\n",
    "splitsA_fever = tmp[\"f0\"]\n",
    "splitsA_cough = tmp[\"f1\"]\n",
    "splitsA_fever,splitsA_cough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 1)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp = modelB.get_score(importance_type=\"weight\")\n",
    "splitsB_fever = tmp[\"f0\"]\n",
    "splitsB_cough = tmp[\"f1\"]\n",
    "splitsB_fever,splitsB_cough"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Gain\n",
    "\n",
    "For some reason XGBoost averages the gain instead of summing as is classically proposed by Brieman, Friedman and others. So we undo the average by multiplying by the split count. (The averaged version of the gain is also inconsistent, but just not with this example.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(33.333277777696765, 66.66672222230325)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp = modelA.get_score(importance_type=\"gain\")\n",
    "gainA_fever = tmp[\"f0\"]*splitsA_fever\n",
    "gainA_cough = tmp[\"f1\"]*splitsA_cough \n",
    "total = gainA_fever+gainA_cough\n",
    "gainA_fever /= total / 100\n",
    "gainA_cough /= total / 100\n",
    "gainA_fever,gainA_cough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "799998.0"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp[\"f0\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "800000.00000125"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp[\"f1\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(56.14035087723146, 43.85964912276855)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp = modelB.get_score(importance_type=\"gain\")\n",
    "gainB_fever = tmp[\"f0\"] * splitsB_fever\n",
    "gainB_cough = tmp[\"f1\"] * splitsB_cough \n",
    "total = gainB_fever + gainB_cough\n",
    "gainB_fever /= total / 100\n",
    "gainB_cough /= total / 100\n",
    "gainB_fever, gainB_cough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "800.00000000125"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp[\"f0\"]*splitsB_fever/2000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1250000.0"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp[\"f1\"]*splitsB_cough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "625.0"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1250000.0/2000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "25.0"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(90+10+0+0)/4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1425.0"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((90-25)**2 + (10-25)**2 + (0-25)**2 + (0-25)**2)/4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1425.0"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((90-25)**2 + (10-25)**2 + (0-25)**2 + (0-25)**2)/4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "800.0"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((90-50)**2 + (10-50)**2 + (0-0)**2 + (0-0)**2)/4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Permutation\n",
    "\n",
    "XGBoost does not implement permtation importance so we compute it ourselves."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def permute_importance(model, y):\n",
    "    vals_fever = []\n",
    "    Xtmp = X.copy()\n",
    "    inds = list(range(Xtmp.shape[0]))\n",
    "    for i in range(1000):\n",
    "        np.random.shuffle(inds)\n",
    "        Xtmp[:,0] = Xtmp[inds,0]\n",
    "        err = y - model.predict(xgb.DMatrix(Xtmp))\n",
    "        vals_fever.append(np.mean(np.sqrt(err*err)))\n",
    "    \n",
    "    vals_cough = []\n",
    "    Xtmp = X.copy()\n",
    "    inds = list(range(Xtmp.shape[0]))\n",
    "    for i in range(1000):\n",
    "        np.random.shuffle(inds)\n",
    "        Xtmp[:,1] = Xtmp[inds,1]\n",
    "        err = y - model.predict(xgb.DMatrix(Xtmp))\n",
    "        vals_cough.append(np.mean(np.sqrt(err*err)))\n",
    "    return np.mean(vals_fever),np.mean(vals_cough)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(19.99126498275, 19.98526500925)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "permuteA_fever,permuteA_cough = permute_importance(modelA, yA)\n",
    "permuteA_fever,permuteA_cough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(20.034424979099999, 25.004065000950632)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "permuteB_fever,permuteB_cough = permute_importance(modelB, yB)\n",
    "permuteB_fever,permuteB_cough"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Weighted Split Count\n",
    "\n",
    "The weighted split count is another option in XGBoost, it is not inconsistent in this example, but is for other scenarios."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'f0': 2000.0, 'f1': 1000.0}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "modelA.get_score(importance_type=\"cover\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'f0': 1000.0, 'f1': 2000.0}"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "modelB.get_score(importance_type=\"cover\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Make plot\n",
    "\n",
    "Here we make the core bar plot for Figure 1 of the paper."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a148349b0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# fever\n",
    "f = pl.figure(figsize=(7,6))\n",
    "pl.subplot(1,2,1)\n",
    "d = 2\n",
    "values_A = [\n",
    "    permuteA_fever,\n",
    "    splitsA_fever,\n",
    "    gainA_fever,\n",
    "    np.abs(shap_valuesA).mean(0)[0],\n",
    "    saabas_valuesA[0,0],\n",
    "    shap_valuesA[0,0]\n",
    "]\n",
    "display_A = [str(int(round(v))) for v in values_A]\n",
    "display_A[2] = str(int(display_A[2]))+\"%\"\n",
    "positions_A = [\n",
    "    1,\n",
    "    4,\n",
    "    7,\n",
    "    10,\n",
    "    13+d,\n",
    "    16+d\n",
    "]\n",
    "values_B = [\n",
    "    permuteA_cough,\n",
    "    splitsA_cough,\n",
    "    gainA_cough,\n",
    "    np.abs(shap_valuesA).mean(0)[1],\n",
    "    saabas_valuesA[0,1],\n",
    "    shap_valuesA[0,1]\n",
    "]\n",
    "display_B = [str(int(round(v))) for v in values_B]\n",
    "display_B[2] = str(int(display_B[2]))+\"%\"\n",
    "positions_B = [\n",
    "    0,\n",
    "    3,\n",
    "    6,\n",
    "    9,\n",
    "    12+d,\n",
    "    15+d\n",
    "]\n",
    "pl.barh(positions_A, values_A, color=\"#008BE0\")\n",
    "pl.barh(positions_B, values_B, color=\"#008BE0\")\n",
    "pl.yticks([])\n",
    "pl.axis('off')\n",
    "for i, v in enumerate(values_A):\n",
    "    pl.text(v + 3, positions_A[i]-0.25, str(display_A[i]), color='#008BE0', fontweight='bold')\n",
    "for i, v in enumerate(values_B):\n",
    "    pl.text(v + 3, positions_B[i]-0.25, str(display_B[i]), color='#008BE0', fontweight='bold')\n",
    "\n",
    "# cough\n",
    "pl.subplot(1,2,2)\n",
    "d = 2\n",
    "values_A = [\n",
    "    permuteB_fever,\n",
    "    splitsB_fever,\n",
    "    gainB_fever,\n",
    "    np.abs(shap_valuesB).mean(0)[0],\n",
    "    saabas_valuesB[0,0],\n",
    "    shap_valuesB[0,0]\n",
    "]\n",
    "display_A = [str(int(round(v))) for v in values_A]\n",
    "display_A[2] = display_A[2]+\"%\"\n",
    "positions_A = [\n",
    "    1,\n",
    "    4,\n",
    "    7,\n",
    "    10,\n",
    "    13+d,\n",
    "    16+d\n",
    "]\n",
    "values_B = [\n",
    "    permuteB_cough,\n",
    "    splitsB_cough,\n",
    "    gainB_cough,\n",
    "    np.abs(shap_valuesB).mean(0)[1],\n",
    "    saabas_valuesB[0,1],\n",
    "    shap_valuesB[0,1]\n",
    "]\n",
    "display_B = [str(int(round(v))) for v in values_B]\n",
    "display_B[2] = str(int(display_B[2]))+\"%\"\n",
    "positions_B = [\n",
    "    0,\n",
    "    3,\n",
    "    6,\n",
    "    9,\n",
    "    12+d,\n",
    "    15+d\n",
    "]\n",
    "pl.barh(positions_A, values_A, color=\"#FF165A\")\n",
    "pl.barh(positions_B, values_B, color=\"#FF165A\")\n",
    "pl.yticks([])\n",
    "pl.axis('off')\n",
    "for i, v in enumerate(values_A):\n",
    "    pl.text(v + 3, positions_A[i]-0.25, str(display_A[i]), color='#FF165A', fontweight='bold')\n",
    "for i, v in enumerate(values_B):\n",
    "    pl.text(v + 3, positions_B[i]-0.25, str(display_B[i]), color='#FF165A', fontweight='bold')\n",
    "    \n",
    "pl.show()\n",
    "#pl.savefig(\"data/bar.pdf\")"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
